/*
 * jngc, Java utility classes by Nicholas Coltharp
 * Copyright (C) 2010 Nicholas Coltharp <ngc1@rice.edu>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.rice.ngc1.util.time;

import java.io.Serializable;

import edu.rice.ngc1.util.EqualsHelper;
import edu.rice.ngc1.util.Primitives;

/**
 * A {@code TimeSource} that can be freely manipulated. Useful
 * primarily for testing.
 */
public class MockTimeSource implements TimeSource, Cloneable, Serializable {

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 3923522204152982610L;

    /**
     * The current time, in nanoseconds.
     */
    private long time;

    /**
     * Initializes this object with a time of 0.
     */
    public MockTimeSource() {
        this(0);
    }

    /**
     * Initializes this object with a specified nano time.
     * 
     * @param start
     *            the time to start with
     */
    public MockTimeSource(long start) {
        this.setNanoTime(start);
    }

    /**
     * Creates a new {@code MockTimeSource} with the time returned by
     * another {@code TimeSource}'s {@code nanoTime()} method.
     * 
     * @param other
     *            the {@code TimeSource} to copy from
     */
    public MockTimeSource(TimeSource other) {
        this(other.nanoTime());
    }

    @Override
    public boolean equals(Object obj) {
        MockTimeSource other = EqualsHelper.check(this, obj);
        if (other == null) {
            return false;
        }
        return (other.time == this.time);
    }

    @Override
    public MockTimeSource clone() {
        return new MockTimeSource(this);
    }

    @Override
    public int hashCode() {
        return Primitives.longToIntBits(time);
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("MockTimeSource(");
        builder.append(time);
        builder.append(")");
        return builder.toString();
    }

    @Override
    public long currentTimeMillis() {
        return time / 1000000;
    }

    @Override
    public long nanoTime() {
        return time;
    }

    /**
     * Sets the time in milliseconds. This is equivalent to calling
     * {@link #setNanoTime(long)} with {@code val} multiplied by
     * 1000000.
     * 
     * @param val
     *            the time in milliseconds for this object to report
     */
    public void setTimeMillis(long val) {
        time = val * 1000000;
    }

    /**
     * Sets the time that will be returned by {@link #nanoTime()}.
     * 
     * @param val
     *            the time that this object will return on the next
     *            call to {@link #nanoTime()}
     */
    public void setNanoTime(long val) {
        time = val;
    }
}
